using Cobra11Undercover;
using SharpDX;
using System;
using System.IO;

namespace Engine.FileFormats3D.C11Undercover
{
    internal struct C11Vertex
    {
        #region Private Fields

        private Color4 diffuseColor;
        private int normalX, normalY, normalZ, normal0;
        private float textureU1, textureV1, textureU2, textureV2;
        private Color4 vertexColor;
        private float x, y, z;

        #endregion Private Fields

        #region Public Constructors

        public C11Vertex(Graphics.VertexStructures.MyOwnVertex.PositionNormalTextured myPositionNormalTextured)
        {
            throw new NotImplementedException("Use the other ctor.");
            //this.x = myPositionNormalTextured.X;
            //this.y = myPositionNormalTextured.Y;
            //this.z = myPositionNormalTextured.Z;
            //this.TextureU1 = myPositionNormalTextured.wrData.UV.X;
            //this.TextureV1 = myPositionNormalTextured.wrData.UV.Y;
            //this.TextureU2 = myPositionNormalTextured.wrData.UV2.X;
            //this.TextureV2 = myPositionNormalTextured.wrData.UV2.Y;
            //this.normalX = (int)(myPositionNormalTextured.Nx * 127);
            //this.normalY = (int)(myPositionNormalTextured.Ny * 127);
            //this.normalZ = (int)(myPositionNormalTextured.Nz * 127);
            //this.normal0 = 0;
            //this.DiffuseColor = new Color4(myPositionNormalTextured.wrData.DiffuseColor);
            //this.VertexColor = new Color4(myPositionNormalTextured.wrData.VertexColor);
        }

        public C11Vertex(Vector3 position, Vector3 normal, Vector3 uV, Vector4 uV2, Color4 diffuseColor, Color4 vertexColor)
        {
            this.x = position.X;
            this.y = position.Y;
            this.z = position.Z;

            this.normalX = (int)(normal.X * 127);
            this.normalY = (int)(normal.Y * 127);
            this.normalZ = (int)(normal.Z * 127);
            this.normal0 = 0;

            this.textureU1 = uV.X;
            this.textureV1 = uV.Y;
            this.textureU2 = uV2.X;
            this.textureV2 = uV2.Y;

            this.diffuseColor = diffuseColor;
            this.vertexColor = vertexColor;
        }

        public C11Vertex(C11UCVertex.C11UCCompleteVertex c11UCCompleteVertex)
        {
            this.x = c11UCCompleteVertex.engineVertex.Position.X;
            this.y = c11UCCompleteVertex.engineVertex.Position.Y;
            this.z = c11UCCompleteVertex.engineVertex.Position.Z;

            this.normalX = (int)(c11UCCompleteVertex.engineVertex.Normal.X * 127);
            this.normalY = (int)(c11UCCompleteVertex.engineVertex.Normal.Y * 127);
            this.normalZ = (int)(c11UCCompleteVertex.engineVertex.Normal.Z * 127);
            this.normal0 = 0;

            this.textureU1 = c11UCCompleteVertex.c11ucVertexData.UV.X;
            this.textureV1 = c11UCCompleteVertex.c11ucVertexData.UV.Y;
            this.textureU2 = c11UCCompleteVertex.c11ucVertexData.UV2.X;
            this.textureV2 = c11UCCompleteVertex.c11ucVertexData.UV2.Y;

            this.diffuseColor = c11UCCompleteVertex.c11ucVertexData.DiffuseColor;
            this.vertexColor = c11UCCompleteVertex.c11ucVertexData.VertexColor;
        }

        #endregion Public Constructors



        #region Public Properties

        public Color4 DiffuseColor
        {
            get { return diffuseColor; }
            set { diffuseColor = value; }
        }

        public int Normal0
        {
            get { return normal0; }
            set { normal0 = value; }
        }

        public int NormalX
        {
            get { return normalX; }
            set { normalX = value; }
        }

        public int NormalY
        {
            get { return normalY; }
            set { normalY = value; }
        }

        public int NormalZ
        {
            get { return normalZ; }
            set { normalZ = value; }
        }

        public float TextureU1
        {
            get { return textureU1; }
            set { textureU1 = value; }
        }

        public float TextureU2
        {
            get { return textureU2; }
            set { textureU2 = value; }
        }

        public float TextureV1
        {
            get { return textureV1; }
            set { textureV1 = value; }
        }

        public float TextureV2
        {
            get { return textureV2; }
            set { textureV2 = value; }
        }

        public Color4 VertexColor
        {
            get { return vertexColor; }
            set { vertexColor = value; }
        }

        public float X
        {
            get { return x; }
            set { x = value; }
        }

        public float Y
        {
            get { return y; }
            set { y = value; }
        }

        public float Z
        {
            get { return z; }
            set { z = value; }
        }

        #endregion Public Properties



        #region Private Properties

        private static int maxNormalX { get; set; }

        private static int maxNormalY { get; set; }

        private static int maxNormalZ { get; set; }

        #endregion Private Properties



        #region Public Methods

        public override string ToString()
        {
            return "vertex Normal0: " + this.Normal0.ToString();
        }

        #endregion Public Methods

        #region Internal Methods

        internal static C11Vertex FromStream(BinaryReader br)
        {
            C11Vertex vertex = new C11Vertex();

            vertex.X = br.ReadSingle();
            vertex.Y = br.ReadSingle();
            vertex.Z = br.ReadSingle();
            vertex.NormalX = (int)br.ReadByte() - 128;
            vertex.NormalY = (int)br.ReadByte() - 128;
            vertex.NormalZ = (int)br.ReadByte() - 128;
            vertex.Normal0 = br.ReadByte();
            vertex.TextureU1 = br.ReadSingle();
            vertex.TextureV1 = br.ReadSingle();
            vertex.TextureU2 = br.ReadSingle();
            vertex.TextureV2 = br.ReadSingle();

            vertex.VertexColor = new Color4((int)br.ReadUInt32());
            //vertex.VertexColor = new Color4()
            //{
            //    Red = br.ReadByte(),
            //    Green = br.ReadByte(),
            //    Blue = br.ReadByte()
            //    Alpha = br.ReadByte(), // Shadow
            //};

            vertex.DiffuseColor = new Color4((int)br.ReadUInt32());
            //vertex.DiffuseColor = new Color4()
            //{
            //    Alpha = br.ReadByte() / 255.0f,
            //    Red = br.ReadByte() / 255.0f,
            //    Green = br.ReadByte() / 255.0f,
            //    Blue = br.ReadByte() / 255.0f
            //};

            //// For testing
            //vertex.TextureU1 = 1;
            //vertex.TextureV1 = 2;
            //vertex.TextureU2 = 3;
            //vertex.TextureV2 = 4;

            //vertex.VertexColor = new Color4()
            //{
            //    Red = 0.10f,
            //    Green = 0.20f,
            //    Blue = 0.3f,
            //    Alpha = 0.123f,
            //};

            // vertex.DiffuseColor = new Color4()
            // {
            //     Red = 1,
            //     Green = 0.66f,
            //     Blue = 0.33f,
            //     Alpha = 0,
            // };

            //vertex.normalX = 0;
            //vertex.normalY = 0;
            //vertex.normalZ = 0;
            //vertex.normal0 = 0;

            return vertex;
        }

        internal void ToStream(BinaryWriter bw)
        {
            bw.Write((float)this.X);
            bw.Write((float)this.Y);//= br.ReadSingle();
            bw.Write((float)this.Z);//= br.ReadSingle();

            byte normalX = (byte)(this.NormalX + 128);
            byte normalY = (byte)(this.NormalY + 128);
            byte normalZ = (byte)(this.NormalZ + 128);

            //normalX = (byte)(127);
            //normalY = (byte)(255);
            //normalZ = (byte)(127);

            C11Vertex.maxNormalX = Math.Min(C11Vertex.maxNormalX, normalX);
            C11Vertex.maxNormalY = Math.Min(C11Vertex.maxNormalY, normalY);
            C11Vertex.maxNormalZ = Math.Min(C11Vertex.maxNormalZ, normalZ);

            bw.Write((byte)normalX);
            bw.Write((byte)normalY);
            bw.Write((byte)normalZ);
            //bw.Write((byte)(this.NormalX + 128));//= (int)br.ReadByte() - 128;
            //bw.Write((byte)(this.NormalY + 128));//= (int)br.ReadByte() - 128;
            //bw.Write((byte)(this.NormalZ + 128));//= (int)br.ReadByte() - 128;
            //bw.Write((byte)(Math.Max(Math.Min(this.NormalX + 128, 0), 255)));//= (int)br.ReadByte() - 128;
            //bw.Write((byte)(Math.Max(Math.Min(this.NormalY + 128, 0), 255)));//= (int)br.ReadByte() - 128;
            //bw.Write((byte)(Math.Max(Math.Min(this.NormalZ + 128, 0), 255)));//= (int)br.ReadByte() - 128;
            bw.Write((byte)(this.Normal0));//= br.ReadByte();
            bw.Write((float)(this.TextureU1 /* / 100.0f */));//= br.ReadSingle();
            bw.Write((float)(this.TextureV1 /* / 100.0f */));//= br.ReadSingle();
            bw.Write((float)(this.TextureU2 /* / 100.0f */));//= br.ReadSingle();
            bw.Write((float)(this.TextureV2 /* / 100.0f */));//= br.ReadSingle();

            if (false)
            {
                bw.Write((byte)0);// tex2
                bw.Write((byte)255);// tex3
                bw.Write((byte)0);
                bw.Write((byte)128);
            }
            else
            {
                //bw.Write(this.VertexColor.ToRgba());// = new Color4((int)br.ReadUInt32());
                bw.Write((byte)this.VertexColor.Blue);
                bw.Write((byte)this.VertexColor.Green);
                bw.Write((byte)this.VertexColor.Red);
                bw.Write((byte)this.VertexColor.Alpha);
            }
            //vertex.VertexColor = new Color4()
            //{
            //    Red = br.ReadByte(),
            //    Green = br.ReadByte(),
            //    Blue = br.ReadByte()
            //    Alpha = br.ReadByte(), // Shadow
            //};
            if (false)
            {
                bw.Write((byte)127);// Blue
                bw.Write((byte)127); // Green
                bw.Write((byte)127); // Red
                bw.Write((byte)255); // Alpha
            }
            else
            {
                // bw.Write(this.DiffuseColor.ToRgba());// = new Color4((int)br.ReadUInt32());
                bw.Write((byte)this.DiffuseColor.Blue);
                bw.Write((byte)this.DiffuseColor.Green);
                bw.Write((byte)this.DiffuseColor.Red);
                bw.Write((byte)this.DiffuseColor.Alpha);
            }
        }

        #endregion Internal Methods
    }
}